<?php
/**
 * Copyright (c) [2019] [吴跃忠]
 * [selibra] is licensed under the Mulan PSL v1.
 * You can use this software according to the terms and conditions of the Mulan PSL v1.
 * You may obtain a copy of Mulan PSL v1 at:
 * http://license.coscl.org.cn/MulanPSL
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v1 for more details.
 */

namespace ckeeper\http;

use ckeeper\dao\ManagerDao;
use ckeeper\entity\ManagerEntity;
use ckeeper\services\RightsService;
use ckeeper\services\RoleService;
use ckeeper\utils\PasswordEncrypt;
use Selibra\Di\DI;
use Selibra\Http\Exception\ResponseException;
use Selibra\Http\Lib\HttpController;

// 错误码定义
define("ERR_10001", 10001);// 路由权限不存在，没有放到权限表中，无法查询权限，所以不允许使用该操作
define("ERR_10002", 10002);// 登录token无效，可能在其他地方被登录了
define("ERR_10003", 10003);// 操作权限不足
define("ERR_10004", 10004);// 安全验证失败，在需要安全密码的操作下，需要输入安全密码才能进行操作，安全密码目前与当前账户登录密码相同
define("ERR_10005", 10005);// 参数缺失
define("ERR_10006", 10006);// 参数格式错误
define("ERR_10007", 10007);// 系统错误
define("ERR_10008", 10008);// 数据不存在，提交的ID查询数据不存在
define("ERR_10009",10009);// 操作被禁止，如操作无法删除的对象时将返回该错误码

abstract class Http extends HttpController
{

    /**
     * 是否进行访问验证
     * @var bool
     */
    protected bool $accessAuth = true;

    /**
     * @var ManagerEntity
     */
    protected ?ManagerEntity $manager;


    /**
     * 请求开始
     * @return bool|void
     * @throws ResponseException
     */
    public function __begin()
    {
        parent::__begin();
        $session = $this->session();
        $pathInfo = $session->getRequest()->getPathInfo();
        // 判断登陆信息等
        // 登录验证
        $token = $session->getRequest()->getCookie('token');
        if (empty($token)) {
            throw new ResponseException($session->getResponse()
                ->setMessage("token无效")
                ->setCode(ERR_10002)
                , ERR_10002);
        }
        /** @var ManagerDao $managerDao */
        $managerDao = DI::getObjectContext(ManagerDao::class);
        $this->manager = $managerDao->getManagerAccountByToken($token);
        if (empty($this->manager)) {
            throw new ResponseException(
                $session->getResponse()
                    ->setCode(ERR_10002)
                    ->setMessage("token无效")
            );
        }

        // 是否进行权限验证
        if (!$this->accessAuth) {
            return true;
        }

        // 获取当前路由权限的Key值
        /** @var RightsService $rightsService */
        $rightsService = DI::getObjectContext(RightsService::class);
        $rights = $rightsService->getRightByRoute($pathInfo,$this->getRequest()->getMethod());
        if (empty($rights)) {
            // 再使用 ANY 进行获取，如果还没有的话就缺少路由权限
            $rights = $rightsService->getRightByRoute($pathInfo,"ANY");
            if( empty($rights) ){
                throw new ResponseException(
                    $session->getResponse()
                        ->setStatus(404)
                        ->setCode(ERR_10001)
                        ->setMessage("路由不存在，请联系超级管理员")
                );
            }
        }
        if ($rights->getVerify()) {
            // 需要进行密码验证
            $verifyPassword = $this->getRequest()->getPost('verifyPassword') ?:
                $this->getRequest()->getDelete('verifyPassword') ?:
                    $this->getRequest()->getPut('verifyPassword');
            if (empty($verifyPassword) || !PasswordEncrypt::checking($verifyPassword, $this->manager->getPassword(), $this->manager->getSalt())) {
                throw new ResponseException(
                    $session->getResponse()
                        ->setCode(ERR_10004)
                        ->setMessage("安全验证失败，密码错误")
                );
            }
        }

        // 超级管理员不判断权限
        if( $this->manager->id === 1 ){
            return true;
        }

        // 权限验证
        $roles = $this->manager->getRoles();
        $roleIds = array_filter(explode(',', $roles));
        $access = [];
        if (!empty($roleIds)) {
            // 权限
            /** @var RoleService $roleService */
            $roleService = DI::getObjectContext(RoleService::class);
            $access = $roleService->getRightsByIds($roleIds);
        }
        if (empty($access) || !in_array($rights->getKey(), $access)) {
            throw new ResponseException(
                $session->getResponse()
                    ->setMessage("权限不足")
                    ->setCode(ERR_10003)
            );
        }
    }


    /**
     * @return string
     */
    public static function outputString(): string
    {
        return "/manage";
    }

}
